package com.lsp.microorder.pay.service.impl;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.lsp.microorder.pay.config.WxPayProperties;
import com.lsp.microorder.pay.param.PayParam;
import com.lsp.microorder.pay.param.PayResultParam;
import com.lsp.microorder.pay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

@Slf4j
@Service
public class WxH5PayServiceImpl implements PayService {

    //    第四方提供的
    @Resource
    private WxPayService wxPayService;

    @Resource
    private WxPayProperties wxPayProperties;


    /**
     * 后端服务端向支付宝系统发送请求，获取二维码链接
     *
     * @param
     * @return
     */
    @Override
    public String createPayOrder(PayParam payParam) {
        //调用微信统一下单接口
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        // orderRequest.setOpenid();
        // 设置支付方式
        orderRequest.setTradeType(WxPayConstants.TradeType.MWEB);
        orderRequest.setNotifyUrl(wxPayProperties.getNotifyUrl()+"?orderNo="+payParam.getTradeNo());
        orderRequest.setOutTradeNo(payParam.getTradeNo());
        orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(payParam.getTotalAmount().toString()));
        orderRequest.setBody(payParam.getSubject());
        orderRequest.setSpbillCreateIp(InetAddress.getLoopbackAddress().getHostAddress());

        //计算签名 给前端使用
        Map<String, String> paySignInfo = new HashMap<>();
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = String.valueOf(System.currentTimeMillis());
        paySignInfo.put("appId", wxPayProperties.getAppId());
        paySignInfo.put("nonceStr", nonceStr);
        paySignInfo.put("timeStamp", timeStamp);
        paySignInfo.put("signType", "MD5");
        String paySign = SignUtils.createSign(paySignInfo, WxPayConstants.SignType.MD5, wxPayProperties.getMchKey(), new String[0]);
        orderRequest.setSign(paySign);

        WxPayMwebOrderResult result = null;
        try {
            result = wxPayService.createOrder(orderRequest);
            log.info("微信统一下单接口调用完成: {}", result);
        } catch (Exception e) {
            log.error("微信统一下单接口调用失败: {}", e.getMessage(), e);
            throw new RuntimeException("微信统一下单接口调用失败");
        }
        return result.getMwebUrl();
    }

    @Override
    public void notify(HttpServletRequest request, HttpServletResponse response, Consumer<PayResultParam> consumer) {
        log.info("wx notify");
        // 回调中返回的参数
        String xmlData = null;
        WxPayOrderNotifyResult notifyResult = null;
        // 针对回调请求返回的结果
        String resultInfo = null;
        try {
            // 微信v2版本，返回的是xml格式数据
            xmlData = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            System.out.println(xmlData);
            notifyResult = wxPayService.parseOrderNotifyResult(xmlData);

            // 成功返回 - SUCCESS,就是"SUCCESS".equals(code)
            if (!"SUCCESS".equals(notifyResult.getResultCode())) {
                resultInfo = WxPayNotifyResponse.fail("微信支付失败");
            } else {
                // 业务订单编号
                String outTradeNo = notifyResult.getOutTradeNo();
                String totalFee = BaseWxPayResult.fenToYuan(notifyResult.getTotalFee());
                BigDecimal totalAmount = new BigDecimal(totalFee);
                // 微信交易订单id
                String tradeNo = notifyResult.getTransactionId();

                log.info("wx notify success");
                // <xml>
                //  <return_code><![CDATA[SUCCESS]]></return_code>
                //  <return_msg><![CDATA[OK]]></return_msg>
                // </xml>
                resultInfo = WxPayNotifyResponse.success("OK");
            }
        } catch (Exception e) {
            e.printStackTrace();
            resultInfo = WxPayNotifyResponse.fail("error");
        }
        System.out.println(resultInfo);
        try {
            response.setContentType("text/xml");
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(resultInfo.getBytes());
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String payStates(String orderNo) {
        /*
         * SUCCESS：支付成功
         * REFUND：转入退款
         * NOTPAY：未支付
         * CLOSED：已关闭
         * REVOKED：已撤销（仅付款码支付会返回）
         * USERPAYING：用户支付中（仅付款码支付会返回）
         * PAYERROR：支付失败（仅付款码支付会返回）
         */
        WxPayOrderQueryResult result = null;
        try {
            // 第一个参数是交易订单id
            result = wxPayService.queryOrder(null, orderNo);
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new RuntimeException("查询支付状态异常");
        }
        System.out.println(result);
        String tradeState = result.getTradeState();
        System.out.println(tradeState);
        if (tradeState.equals("NOTPAY") || tradeState.equals("UUSERPAYING")) {
            throw new RuntimeException("等待支付");
        }
        String outTradeNo = result.getTransactionId();
        return outTradeNo;
    }

    @Override
    public void closePay(String orderNo) {
        try {
            WxPayOrderCloseResult wxPayOrderCloseResult = wxPayService.closeOrder(orderNo);
            System.out.println(wxPayOrderCloseResult);
            System.out.println(wxPayOrderCloseResult.getResultCode());
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new RuntimeException("关闭订单异常：" + e.getReturnMsg());
        }
    }

    @Override
    public void returnNotify(HttpServletRequest request, HttpServletResponse response) {

    }

    /**
     * 获取ip
     *
     * @return
     */
    public String getIpAddress() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            // 若以上方式均为获取到ip则证明获得客户端并没有采用反向代理直接使用getRemoteAddr()获取客户端的ip地址
            ip = request.getRemoteAddr();
        }
        // 多个路由时，取第一个非unknown的ip
        final String[] arr = ip.split(",");
        for (final String str : arr) {
            if (!"unknown".equalsIgnoreCase(str)) {
                ip = str;
                break;
            }
        }
        return ip;
    }


}
